#include <stdio.h>

/*
 * 虚函数表的模拟情形
 */

void demo_1(void)
{
	printf("Demo 1\n");
}

void demo_2(void)
{
	printf("Demo 2\n");
}

void call_demo(void **x)
{
	((void (*)(void)) x[0])();
	((void (*)(void)) x[1])();
}

int main()
{
	static void *x[2] = {(void *)demo_1, (void *)demo_2};
	/* 
		注意:如果在程序之中初始化代码(即x[0]=(void *)demo_1,...)，编译器会在运行时生成改写函数的偏移量的合适代码，
		这与虚函数表绝对不一样。相反，在声明的同时初始化数组会使准备好的指针放入代码段，这与实际的虚函数表类似。
		(这也有助于节省CPU时钟周期)
	 */

	 call_demo(&x[0]);

	 return 0;
}

#if 0
/*
 * intel
 */
0000000000001149 <demo_1>:
    1149:	f3 0f 1e fa          	endbr64 
    114d:	55                   	push   %rbp
    114e:	48 89 e5             	mov    %rsp,%rbp
    1151:	48 8d 3d ac 0e 00 00 	lea    0xeac(%rip),%rdi        # 2004 <_IO_stdin_used+0x4>
    1158:	e8 f3 fe ff ff       	callq  1050 <puts@plt>
    115d:	90                   	nop
    115e:	5d                   	pop    %rbp
    115f:	c3                   	retq   

0000000000001160 <demo_2>:
    1160:	f3 0f 1e fa          	endbr64 
    1164:	55                   	push   %rbp
    1165:	48 89 e5             	mov    %rsp,%rbp
    1168:	48 8d 3d 9c 0e 00 00 	lea    0xe9c(%rip),%rdi        # 200b <_IO_stdin_used+0xb>
    116f:	e8 dc fe ff ff       	callq  1050 <puts@plt>
    1174:	90                   	nop
    1175:	5d                   	pop    %rbp
    1176:	c3                   	retq   

0000000000001177 <call_demo>:
    1177:	f3 0f 1e fa          	endbr64 
    117b:	55                   	push   %rbp
    117c:	48 89 e5             	mov    %rsp,%rbp
    117f:	48 83 ec 10          	sub    $0x10,%rsp	// rsp-=0x10
    1183:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)	// rbp-0x8=rdi
    1187:	48 8b 45 f8          	mov    -0x8(%rbp),%rax	// rax=rbp-0x8
    118b:	48 8b 00             	mov    (%rax),%rax	// rax=(rax)
    118e:	ff d0                	callq  *%rax		// rax()
    1190:	48 8b 45 f8          	mov    -0x8(%rbp),%rax	// rax=rbp-0x8
    1194:	48 83 c0 08          	add    $0x8,%rax	// rax+=0x8
    1198:	48 8b 00             	mov    (%rax),%rax	// rax=(rax)
    119b:	ff d0                	callq  *%rax		// rax()
    119d:	90                   	nop
    119e:	c9                   	leaveq 
    119f:	c3                   	retq   

00000000000011a0 <main>:
    11a0:	f3 0f 1e fa          	endbr64 
    11a4:	55                   	push   %rbp
    11a5:	48 89 e5             	mov    %rsp,%rbp
    11a8:	48 8d 3d 61 2e 00 00 	lea    0x2e61(%rip),%rdi        # 4010 <x.2326>		????
    11af:	e8 c3 ff ff ff       	callq  1177 <call_demo>	// call_demo(rdi)
    11b4:	b8 00 00 00 00       	mov    $0x0,%eax
    11b9:	5d                   	pop    %rbp
    11ba:	c3                   	retq   
    11bb:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

/*
 * arm
 */
000000000040055c <demo_1>:
  40055c:	a9bf7bfd 	stp	x29, x30, [sp, #-16]!
  400560:	910003fd 	mov	x29, sp
  400564:	90000000 	adrp	x0, 400000 <_init-0x3e8>
  400568:	911a8000 	add	x0, x0, #0x6a0
  40056c:	97ffffb9 	bl	400450 <puts@plt>
  400570:	d503201f 	nop
  400574:	a8c17bfd 	ldp	x29, x30, [sp], #16
  400578:	d65f03c0 	ret

000000000040057c <demo_2>:
  40057c:	a9bf7bfd 	stp	x29, x30, [sp, #-16]!
  400580:	910003fd 	mov	x29, sp
  400584:	90000000 	adrp	x0, 400000 <_init-0x3e8>
  400588:	911aa000 	add	x0, x0, #0x6a8
  40058c:	97ffffb1 	bl	400450 <puts@plt>
  400590:	d503201f 	nop
  400594:	a8c17bfd 	ldp	x29, x30, [sp], #16
  400598:	d65f03c0 	ret

000000000040059c <call_demo>:
  40059c:	a9be7bfd 	stp	x29, x30, [sp, #-32]!
  4005a0:	910003fd 	mov	x29, sp
  4005a4:	f9000fa0 	str	x0, [x29, #24]		// x29+24=x0
  4005a8:	f9400fa0 	ldr	x0, [x29, #24]		// x0=x29+24
  4005ac:	f9400000 	ldr	x0, [x0]		// x0=(x0)=(x29+24)
  4005b0:	d63f0000 	blr	x0			// x0()
  4005b4:	f9400fa0 	ldr	x0, [x29, #24]		// x0=x29+24
  4005b8:	91002000 	add	x0, x0, #0x8		// x0+=8
  4005bc:	f9400000 	ldr	x0, [x0]		// x0=(x0)
  4005c0:	d63f0000 	blr	x0			// x0()
  4005c4:	d503201f 	nop
  4005c8:	a8c27bfd 	ldp	x29, x30, [sp], #32
  4005cc:	d65f03c0 	ret

00000000004005d0 <main>:
  4005d0:	a9bf7bfd 	stp	x29, x30, [sp, #-16]!
  4005d4:	910003fd 	mov	x29, sp
  4005d8:	b0000080 	adrp	x0, 411000 <__libc_start_main@GLIBC_2.17>
  4005dc:	9100c000 	add	x0, x0, #0x30		// x0=411030
  4005e0:	97ffffef 	bl	40059c <call_demo>	// call_demo(x0)
  4005e4:	52800000 	mov	w0, #0x0                   	// #0
  4005e8:	a8c17bfd 	ldp	x29, x30, [sp], #16
  4005ec:	d65f03c0 	ret


#endif
